﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;

namespace Examples.CAMLFilter
{

    /// <summary>
    /// Класс контролов, готовящих значения для фильтров
    /// </summary>
    public class FieldControl
    {
        /// <summary>
        /// Название поля, по которому фильтруем
        /// </summary>
        public String Title { get { return this.Field.Title; } }

        /// <summary>
        /// Контрол для ввода значений фильтра
        /// </summary>
        public BaseInputControl Input;

        /// <summary>
        /// Подсказка для контрола
        /// </summary>
        public String ToolTip;

        /// <summary>
        /// Фильтр, для которого вводим значения
        /// </summary>
        public Filter Filter;

        /// <summary>
        /// Поле, по которому фильтруем
        /// </summary>
        public SPField Field;

        /// <summary>
        /// Локаль для подсказок и прочих текстов
        /// </summary>
        public Locale Locale;

        /// <summary>
        /// Номер фильтра - для унимкальности ID
        /// </summary>
        public int Id;


        /// <summary>
        /// Конструктор
        /// </summary>
        /// <param name="filter">Фильтр</param>
        /// <param name="field">Поле списка, по которому фильтруем</param>
        /// <param name="locale">Текущая локаль</param>
        public FieldControl(Filter filter, SPField field, Locale locale, int width, int id)
        {
            this.Filter = filter;
            this.Field = field;
            this.Locale = locale;
            this.Id = id;

            // Вычисляем справку
            String hint = String.Format("$Resources:WPECondHint{0}{1};", (this.Filter.IsMulti ? "Multi" : ""), this.Filter.Condition.ToString());
            this.ToolTip = SPUtility.GetLocalizedString(hint, "Examples.CAMLFilter", Locale);
            if (this.ToolTip.Equals(hint))
            {
                hint = String.Format("$Resources:WPECondHint{0};", this.Filter.Condition.ToString());
                this.ToolTip = SPUtility.GetLocalizedString(hint, "Examples.CAMLFilter", Locale);
                if (this.ToolTip.Equals(hint)) this.ToolTip = String.Empty;
            }
            // Для единичного контрола даты
            if (this.Filter.FieldType.Equals(SPFieldType.DateTime.ToString()) && !this.Filter.IsMulti)
            {
                Input = new DateInputControl() { FieldControl = this, TextBoxWidth = width };
            }
            // Для даты с диапазонами
            else if (this.Filter.FieldType.Equals(SPFieldType.DateTime.ToString()) && (this.Filter.Condition == Condition.Between || this.Filter.Condition == Condition.NotBetween))
            {
                Input = new DateBetweenInputControl() { FieldControl = this, TextBoxWidth = width };
            }
            // Для контрола Lookup с точными сравнениями
            else if (this.Filter.FieldType.Equals(SPFieldType.Lookup.ToString()) &&
                (this.Filter.Condition != Condition.BeginsWith && this.Filter.Condition != Condition.Contains)
                )
            {
                Input = new LookupInputControl() { FieldControl = this, TextBoxWidth = width };
            }
            // Для контрола User с точными сравнениями
            else if (this.Filter.FieldType.Equals(SPFieldType.User.ToString()) &&
                (this.Filter.Condition != Condition.BeginsWith && this.Filter.Condition != Condition.Contains)
                )
            {
                Input = new PeopleInputControl() { FieldControl = this, TextBoxWidth = width };
            }
            // Для единичного контрола Boolean
            else if (this.Filter.FieldType.Equals(SPFieldType.Boolean.ToString()) && !this.Filter.IsMulti)
            {
                Input = new BooleanInputControl() { FieldControl = this, TextBoxWidth = width };
            }
            // Для единичного контрола Choice с точными сравнениями и без добавленных пользователем значений
            else if (this.Filter.FieldType.Equals(SPFieldType.Choice.ToString()) &&
                !this.Filter.IsMulti &&
                (this.Filter.Condition != Condition.BeginsWith && this.Filter.Condition != Condition.Contains) &&
                (this.Field is SPFieldChoice) && !((SPFieldChoice)this.Field).FillInChoice)
            {
                Input = new ChoiceInputControl() { FieldControl = this, TextBoxWidth = width };
            }
            // Для чисел (единичных и множества)
            else if (this.Filter.FieldType.Equals(SPFieldType.Number.ToString()) || this.Filter.FieldType.Equals(SPFieldType.Currency.ToString()))
            {
                ToolTip += (String.IsNullOrEmpty(this.ToolTip) ? "" : " ") + SPUtility.GetLocalizedString("$Resources:WPFDecimalDelimiter", "Examples.CAMLFilter", Locale);
                // Для диапазонов
                if (this.Filter.Condition == Condition.Between || this.Filter.Condition == Condition.NotBetween)
                {
                    Input = new NumberBetweenInputControl() { FieldControl = this, TextBoxWidth = width };
                }
                else
                {
                    Input = new NumberInputControl() { FieldControl = this, TextBoxWidth = width };
                    if (this.Filter.IsMulti) ToolTip += " " + String.Format(SPUtility.GetLocalizedString("$Resources:WPFTextMulti", "Examples.CAMLFilter", Locale), this.Filter.Delimiter);
                }
            }

            // Custom field type related code
            //else if (this.Filter.FieldType.Equals(CustomFieldTypes.MyLookup)) &&
            //{
            //    Input = new MyLookupInputControl() { FieldControl = this, TextBoxWidth = width };
            //}

            // Дефолтный контрол - просто текст
            else
            {
                // Для диапазонов
                if (this.Filter.Condition == Condition.Between || this.Filter.Condition == Condition.NotBetween)
                {
                    Input = new TextBetweenInputControl() { FieldControl = this, TextBoxWidth = width };
                }
                else
                {
                    Input = new TextInputControl() { FieldControl = this, TextBoxWidth = width };
                    if (this.Filter.IsMulti) ToolTip += (String.IsNullOrEmpty(this.ToolTip) ? "" : " ") + String.Format(SPUtility.GetLocalizedString("$Resources:WPFTextMulti", "Examples.CAMLFilter", Locale), this.Filter.Delimiter);
                }
            }
        }

        /// <summary>
        /// Имя куки, в которую надо сохранять значение
        /// </summary>
        public String CookieName
        {
            get { return "cf" + this.Filter.FieldName; }
        }

    }

    /// <summary>
    /// Базовый абстрактный класс для полей ввода
    /// </summary>
    public abstract class BaseInputControl : Table
    {

        /// <summary>
        /// Ширина текстового поля ввода
        /// </summary>
        public int TextBoxWidth;

        /// <summary>
        /// Для кого стараемся
        /// </summary>
        public FieldControl FieldControl;

        /// <summary>
        /// Кнопка очистки значений
        /// </summary>
        protected ImageButton btnClear;

        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            if (!String.IsNullOrEmpty(FieldControl.ToolTip)) this.ToolTip = FieldControl.ToolTip;

            this.Style.Add("padding", "0px;");
            TableRow row = new TableRow();
            this.Rows.Add(row);

            TableCell cInput = new TableCell();
            cInput.Style.Add("white-space", "nowrap;");
            row.Cells.Add(cInput);

            // Добавляем кнопку очистки
            TableCell cClear = new TableCell();
            row.Cells.Add(cClear);
            btnClear = new ImageButton()
            {
                ImageUrl = "/_layouts/images/filteroff.gif",
                CausesValidation = false
            };

            // Там, где надо - будем явно включать обработку
            //btnClear.Click += new ImageClickEventHandler(btnClear_Click);
            cClear.Controls.Add(btnClear);

            // Добавляем индивидуальные контролы 
            addInputControls(cInput);


        }

        public void EnsureControls()
        {
            this.EnsureChildControls();
        }

        protected abstract void addInputControls(TableCell cell);

        /// <summary>
        /// Значение в контролах
        /// </summary>
        public abstract String Value { get; set; }

        /// <summary>
        /// Настройка контролов даты, нужна в некоторых дочках
        /// </summary>
        protected TextBox prepareDateControl(DateTimeControl dc)
        {
            dc.Calendar = (SPCalendarType)FieldControl.Field.ParentList.ParentWeb.RegionalSettings.CalendarType;
            dc.HijriAdjustment = FieldControl.Field.ParentList.ParentWeb.RegionalSettings.AdjustHijriDays;
            dc.TimeZoneID = FieldControl.Field.ParentList.ParentWeb.RegionalSettings.TimeZone.ID;
            dc.FirstDayOfWeek = (int)FieldControl.Field.ParentList.ParentWeb.RegionalSettings.FirstDayOfWeek;
            dc.FirstWeekOfYear = FieldControl.Field.ParentList.ParentWeb.RegionalSettings.FirstWeekOfYear;
            dc.LocaleId = FieldControl.Field.ParentList.ParentWeb.Locale.LCID;

            TextBox txt = null;
            foreach (WebControl ctl in dc.Controls)
            {
                if (ctl is TextBox && ctl.ID.EndsWith("Date"))
                {
                    txt = (TextBox)ctl;
                    txt.Columns = 10;
                    ctl.BorderStyle = BorderStyle.Solid;
                    ctl.BorderWidth = 1;
                }
                else if (ctl is DropDownList)
                {
                    ctl.BorderStyle = BorderStyle.Solid;
                    ctl.BorderWidth = 1;
                }
            }
            return txt;

        }

        /// <summary>
        /// Серверный метод очистки поля. Где можем - вместо него используем клиентскую очистку значений
        /// </summary>
        protected void btnClear_Click(object sender, ImageClickEventArgs e)
        {
            this.Value = null;
        }

    }

    /// <summary>
    /// Контрол для полей типа Text, он же дефолтный
    /// </summary>
    class TextInputControl : BaseInputControl
    {

        protected TextBox iText;

        public override String Value
        {
            get
            {
                EnsureChildControls();
                return iText.Text;
            }
            set
            {
                EnsureChildControls();
                iText.Text = value;
            }
        }

        protected override void addInputControls(TableCell cell)
        {
            iText = new TextBox()
            {
                ID = String.Format("tic{0}_{1}", FieldControl.Id, FieldControl.Filter.Value),
                CssClass = "ms-input",
                Width = Unit.Pixel(TextBoxWidth),
                BorderStyle = BorderStyle.Solid,
                BorderWidth = 1
            };

            cell.Controls.Add(iText);

            // Отпишемся от стандартного 
            btnClear.Click -= btnClear_Click;
            // И сделаем очистку на клиенте
            btnClear.OnClientClick = String.Format("javascript:document.getElementById('{0}').value='';", iText.ClientID);

        }

    }

    /// <summary>
    /// Контрол для числовых полей
    /// </summary>
    class NumberInputControl : TextInputControl
    {
        protected override void addInputControls(TableCell cell)
        {
            base.addInputControls(cell);

            RegularExpressionValidator regVal = new RegularExpressionValidator();
            regVal.ControlToValidate = iText.ID;
            regVal.ValidationExpression = String.Format("^([\\d{0}\\.\\-\\+])*$", FieldControl.Filter.IsMulti ? Regex.Escape(FieldControl.Filter.Delimiter) : "");
            regVal.EnableClientScript = true;
            regVal.Display = ValidatorDisplay.Dynamic;
            regVal.ErrorMessage = "<br/>" + SPUtility.GetLocalizedString("$Resources:WPFErrBadNumber", "Examples.CAMLFilter", FieldControl.Locale);
            cell.Controls.Add(regVal);

        }

    }

    /// <summary>
    /// Контрол для диапазона текстовых полей
    /// </summary>
    class TextBetweenInputControl : BaseInputControl
    {
        protected TextBox sText;
        protected TextBox eText;

        protected CustomValidator cVal;

        public override String Value
        {
            get
            {
                EnsureChildControls();
                String res = sText.Text;
                if (!String.IsNullOrEmpty(eText.Text))
                    res += FieldControl.Filter.Delimiter + eText.Text;
                return res;
            }
            set
            {
                EnsureChildControls();
                string[] vals = { };
                if (!String.IsNullOrEmpty(value))
                    vals = value.Split(new string[] { FieldControl.Filter.Delimiter }, StringSplitOptions.RemoveEmptyEntries);

                sText.Text = (vals.Length > 0 ? vals[0] : null);
                eText.Text = (vals.Length > 1 ? vals[1] : null);
            }
        }

        protected override void addInputControls(TableCell cell)
        {

            cell.Controls.Add(new LiteralControl(SPUtility.GetLocalizedString("$Resources:From", "Examples.CAMLFilter", FieldControl.Locale) + "&nbsp;"));

            sText = new TextBox()
            {
                ID = String.Format("tbic{0}_s_{1}", FieldControl.Id, FieldControl.Filter.Value),
                Width = Unit.Pixel(TextBoxWidth / 2),
                BorderStyle = BorderStyle.Solid,
                BorderWidth = 1
            };
            cell.Controls.Add(sText);

            cell.Controls.Add(new LiteralControl("&nbsp;" + SPUtility.GetLocalizedString("$Resources:Till", "Examples.CAMLFilter", FieldControl.Locale) + "&nbsp;"));

            eText = new TextBox()
            {
                ID = String.Format("tbic{0}_e_{1}", FieldControl.Id, FieldControl.Filter.Value),
                Width = Unit.Pixel(TextBoxWidth / 2),
                BorderStyle = BorderStyle.Solid,
                BorderWidth = 1
            };
            cell.Controls.Add(eText);

            // Отпишемся от стандартного 
            btnClear.Click -= btnClear_Click;
            // И сделаем очистку на клиенте
            btnClear.OnClientClick = String.Format("javascript:document.getElementById('{0}').value='';document.getElementById('{1}').value='';", sText.ClientID, eText.ClientID);

            // Кастомный валидатор
            cVal = new CustomValidator();
            cVal.EnableClientScript = true;
            cVal.ServerValidate += new ServerValidateEventHandler(ServerValidate);
            cVal.ErrorMessage = "<br/>" + SPUtility.GetLocalizedString("$Resources:WPFErrNeedBothValues", "Examples.CAMLFilter", FieldControl.Locale);
            cVal.Display = ValidatorDisplay.Dynamic;
            cell.Controls.Add(cVal);


        }

        protected virtual void ServerValidate(object source, ServerValidateEventArgs args)
        {
            args.IsValid = (String.IsNullOrEmpty(sText.Text) && String.IsNullOrEmpty(eText.Text)) || (!String.IsNullOrEmpty(sText.Text) && !String.IsNullOrEmpty(eText.Text));
        }

    }

    /// <summary>
    /// Контрол для диапазона числовых полей
    /// </summary>
    class NumberBetweenInputControl : TextBetweenInputControl
    {
        static Regex validNumber = new Regex("^([\\d{0}\\.\\-\\+])*$", RegexOptions.Compiled | RegexOptions.IgnoreCase);

        // Валидация слегка поменялась
        protected override void ServerValidate(object source, ServerValidateEventArgs args)
        {
            if (!((String.IsNullOrEmpty(sText.Text) && String.IsNullOrEmpty(eText.Text)) || (!String.IsNullOrEmpty(sText.Text) && !String.IsNullOrEmpty(eText.Text))))
            {
                cVal.ErrorMessage = "<br/>" + SPUtility.GetLocalizedString("$Resources:WPFErrNeedBothValues", "Examples.CAMLFilter", FieldControl.Locale);
                args.IsValid = false;
                return;
            }

            if (!validNumber.IsMatch(sText.Text) || !validNumber.IsMatch(eText.Text))
            {
                cVal.ErrorMessage = "<br/>" + SPUtility.GetLocalizedString("$Resources:WPFErrBadNumber", "Examples.CAMLFilter", FieldControl.Locale);
                args.IsValid = false;
            }

        }

    }

    /// <summary>
    /// Базовый контрол для полей типа DropDownList
    /// </summary>
    abstract class DropDownInputControl : BaseInputControl
    {

        protected DropDownList iList;

        public override String Value
        {
            get
            {
                EnsureChildControls();
                return (iList.SelectedIndex != -1) ? iList.SelectedValue : null;
            }
            set
            {
                EnsureChildControls();
                if (iList.Items.FindByValue(value) != null)
                    iList.SelectedValue = value;
                else
                    iList.SelectedIndex = -1;
            }
        }


        protected override void addInputControls(TableCell cell)
        {
            iList = new DropDownList()
            {
                ID = String.Format("ddic{0}_{1}", FieldControl.Id, FieldControl.Filter.Value),
                CssClass = "ms-input",
                BorderStyle = BorderStyle.Solid,
                BorderWidth = 1
            };
            iList.Items.Add(new ListItem("", ""));
            cell.Controls.Add(iList);

            // Отпишемся от стандартного 
            btnClear.Click -= btnClear_Click;
            // И сделаем очистку на клиенте
            btnClear.OnClientClick = String.Format("javascript:document.getElementById('{0}').selectedIndex = 0;", iList.ClientID);

        }
    }

    /// <summary>
    /// Контрол для полей типа Boolean
    /// </summary>
    class BooleanInputControl : DropDownInputControl
    {
        protected override void addInputControls(TableCell cell)
        {
            base.addInputControls(cell);
            iList.Items.Add(new ListItem(SPUtility.GetLocalizedString("$Resources:Yes", "Examples.CAMLFilter", FieldControl.Locale), "1"));
            iList.Items.Add(new ListItem(SPUtility.GetLocalizedString("$Resources:No", "Examples.CAMLFilter", FieldControl.Locale), "0"));
        }
    }

    /// <summary>
    /// Контрол для полей типа Choice
    /// </summary>
    class ChoiceInputControl : DropDownInputControl
    {
        protected override void addInputControls(TableCell cell)
        {
            base.addInputControls(cell);

            // Берем значения из списка
            if (FieldControl.Field is SPFieldChoice)
            {
                foreach (String choice in ((SPFieldChoice)FieldControl.Field).Choices)
                    iList.Items.Add(new ListItem(choice));
            }
        }
    }

    /// <summary>
    /// Контрол для полей типа DateTime
    /// </summary>
    class DateInputControl : BaseInputControl
    {
        DateTimeControl iDate;
        TextBox tbDate;

        public override String Value
        {
            get
            {
                EnsureChildControls();
                String res = null;
                try
                {
                    if (!String.IsNullOrEmpty(tbDate.Text) && iDate.IsValid)
                        res = SPUtility.CreateISO8601DateTimeFromSystemDateTime(iDate.SelectedDate);
                    else
                        iDate.ClearSelection();
                }
                catch (Exception) { }
                return res;
            }
            set
            {
                EnsureChildControls();
                try
                {
                    if (!String.IsNullOrEmpty(value))
                        iDate.SelectedDate = SPUtility.CreateDateTimeFromISO8601DateTimeString(value);
                    else
                        iDate.ClearSelection();
                }
                catch (Exception) { }
            }
        }

        protected override void addInputControls(TableCell cell)
        {
            iDate = new DateTimeControl()
            {
                ID = String.Format("dic{0}_{1}", FieldControl.Id, FieldControl.Filter.Value),
                CssClassTextBox = "ms-dtinput"
            };

            iDate.DateOnly = !FieldControl.Filter.IncludeTimeValue;

            tbDate = prepareDateControl(iDate);

            cell.Controls.Add(iDate);

            // И сделаем очистку на клиенте
            btnClear.OnClientClick = FieldControl.Filter.IncludeTimeValue ?
                String.Format("javascript:document.getElementById('{0}').value='';document.getElementById('{1}').selectedIndex = 0;document.getElementById('{2}').selectedIndex = 0;", iDate.FindControl(iDate.ID + "Date").ClientID, iDate.FindControl(iDate.ID + "DateHours").ClientID, iDate.FindControl(iDate.ID + "DateMinutes").ClientID) :
                String.Format("javascript:document.getElementById('{0}').value='';", iDate.FindControl(iDate.ID + "Date").ClientID);


        }


    }

    /// <summary>
    /// Контрол для диапазона текстовых полей
    /// </summary>
    class DateBetweenInputControl : BaseInputControl
    {
        DateTimeControl sDate;
        DateTimeControl eDate;

        TextBox sText;
        TextBox eText;

        protected CustomValidator cVal;

        public override String Value
        {
            get
            {
                EnsureChildControls();

                String res = sValue;
                if (!String.IsNullOrEmpty(eValue))
                    res += FieldControl.Filter.Delimiter + eValue;
                return res;
            }
            set
            {
                EnsureChildControls();
                string[] vals = { };
                if (!String.IsNullOrEmpty(value))
                    vals = value.Split(new string[] { FieldControl.Filter.Delimiter }, StringSplitOptions.RemoveEmptyEntries);

                sValue = (vals.Length > 0) ? vals[0] : null;
                eValue = (vals.Length > 1) ? vals[1] : null;
            }
        }


        String sValue
        {
            get
            {
                EnsureChildControls();
                String res = null;
                try
                {
                    if (!String.IsNullOrEmpty(sText.Text) && sDate.IsValid)
                        res = SPUtility.CreateISO8601DateTimeFromSystemDateTime(sDate.SelectedDate);
                    else
                        sDate.ClearSelection();
                }
                catch (Exception) { }
                return res;
            }
            set
            {
                EnsureChildControls();
                if (!String.IsNullOrEmpty(value))
                {
                    try
                    {
                        if (!String.IsNullOrEmpty(value))
                            sDate.SelectedDate = SPUtility.CreateDateTimeFromISO8601DateTimeString(value);
                        else
                            sDate.ClearSelection();
                    }
                    catch (Exception) { }
                }
                else
                {
                    sDate.ClearSelection();
                }
            }
        }


        String eValue
        {
            get
            {
                EnsureChildControls();
                String res = null;
                try
                {
                    if (!String.IsNullOrEmpty(eText.Text) && eDate.IsValid)
                        res = SPUtility.CreateISO8601DateTimeFromSystemDateTime(eDate.SelectedDate);
                    else
                        eDate.ClearSelection();
                }
                catch (Exception) { }
                return res;
            }
            set
            {
                EnsureChildControls();
                if (!String.IsNullOrEmpty(value))
                {
                    try
                    {
                        if (!String.IsNullOrEmpty(value))
                            eDate.SelectedDate = SPUtility.CreateDateTimeFromISO8601DateTimeString(value);
                        else
                            eDate.ClearSelection();
                    }
                    catch (Exception) { }
                }
                else
                {
                    eDate.ClearSelection();
                }
            }
        }


        protected override void addInputControls(TableCell cell)
        {
            Table t = new Table() { CellPadding = 0, CellSpacing = 0 };
            TableRow tr = new TableRow();
            t.Rows.Add(tr);

            cell.Controls.Add(t);

            TableCell c1 = new TableCell();
            tr.Cells.Add(c1);

            c1.Controls.Add(new LiteralControl(SPUtility.GetLocalizedString("$Resources:From", "Examples.CAMLFilter", FieldControl.Locale) + "&nbsp;"));

            TableCell c2 = new TableCell();
            tr.Cells.Add(c2);

            sDate = new DateTimeControl()
            {
                ID = String.Format("dbic{0}_s_{1}", FieldControl.Id, FieldControl.Filter.Value),
                CssClassTextBox = "ms-dtinput"
            };

            sDate.DateOnly = !FieldControl.Filter.IncludeTimeValue;

            sText = prepareDateControl(sDate);

            c2.Controls.Add(sDate);

            TableCell c3 = new TableCell();
            tr.Cells.Add(c3);

            c3.Controls.Add(new LiteralControl("&nbsp;" + SPUtility.GetLocalizedString("$Resources:Till", "Examples.CAMLFilter", FieldControl.Locale) + "&nbsp;"));

            eDate = new DateTimeControl()
            {
                ID = String.Format("dbic{0}_e_{1}", FieldControl.Id, FieldControl.Filter.Value),
                CssClassTextBox = "ms-dtinput"
            };

            TableCell c4 = new TableCell();
            tr.Cells.Add(c4);

            eDate.DateOnly = !FieldControl.Filter.IncludeTimeValue;

            eText = prepareDateControl(eDate);

            c4.Controls.Add(eDate);


            // И сделаем очистку на клиенте
            btnClear.OnClientClick = FieldControl.Filter.IncludeTimeValue ?
                String.Format("javascript:document.getElementById('{0}').value='';document.getElementById('{1}').selectedIndex = 0;document.getElementById('{2}').selectedIndex = 0;document.getElementById('{3}').value='';document.getElementById('{4}').selectedIndex = 0;document.getElementById('{5}').selectedIndex = 0;", sDate.FindControl(sDate.ID + "Date").ClientID, sDate.FindControl(sDate.ID + "DateHours").ClientID, sDate.FindControl(sDate.ID + "DateMinutes").ClientID, eDate.FindControl(eDate.ID + "Date").ClientID, eDate.FindControl(eDate.ID + "DateHours").ClientID, eDate.FindControl(eDate.ID + "DateMinutes").ClientID) :
                String.Format("javascript:document.getElementById('{0}').value='';document.getElementById('{1}').value='';", sDate.FindControl(sDate.ID + "Date").ClientID, eDate.FindControl(eDate.ID + "Date").ClientID);

            // Кастомный валидатор
            cVal = new CustomValidator();
            cVal.EnableClientScript = true;
            cVal.ServerValidate += new ServerValidateEventHandler(ServerValidate);
            cVal.ErrorMessage = SPUtility.GetLocalizedString("$Resources:WPFErrNeedBothValues", "Examples.CAMLFilter", FieldControl.Locale);
            cVal.Display = ValidatorDisplay.Dynamic;
            cell.Controls.Add(cVal);

        }

        protected virtual void ServerValidate(object source, ServerValidateEventArgs args)
        {
            args.IsValid = (String.IsNullOrEmpty(sValue) && String.IsNullOrEmpty(eValue)) || (!String.IsNullOrEmpty(sValue) && !String.IsNullOrEmpty(eValue));
        }

    }

    /// <summary>
    /// Контрол для полей типа Lookup
    /// </summary>
    class LookupInputControl : BaseInputControl
    {

        protected ListItemPicker iLookup;

        public override String Value
        {
            get
            {
                EnsureChildControls();

                List<String> vals = new List<String>();

                foreach (PickerEntity ent in iLookup.Entities)
                    vals.Add(this.FieldControl.Filter.UseLookupId ? ent.Key : ent.DisplayText);

                return vals.Count == 0 ? null : String.Join(String.IsNullOrEmpty(this.FieldControl.Filter.Delimiter) ? Filter.DefaultDelimiter : this.FieldControl.Filter.Delimiter, vals.ToArray());
            }
            set
            {
                EnsureChildControls();
                iLookup.Entities.Clear();
                string[] vals = { };
                if (!String.IsNullOrEmpty(value))
                {
                    vals = FieldControl.Filter.IsMulti ? value.Split(new string[] { FieldControl.Filter.Delimiter }, StringSplitOptions.RemoveEmptyEntries) : new string[] { value };

                    foreach (String val in vals)
                    {
                        PickerEntity entity = new PickerEntity();
                        entity.Key = entity.DisplayText = val;
                        entity = iLookup.ValidateEntity(entity);
                        if (entity.IsResolved)
                            iLookup.Entities.Add(entity);

                    }
                }
            }
        }

        protected override void addInputControls(TableCell cell)
        {
            iLookup = new ListItemPicker()
            {
                ID = String.Format("lic{0}_{1}", FieldControl.Id, FieldControl.Filter.Value),
                CssClass = "ms-usereditor",
                ToolTip = this.ToolTip
            };
            iLookup.PickerData = new ListItemPickerData(((SPFieldLookup)FieldControl.Field).LookupWebId, new Guid(((SPFieldLookup)FieldControl.Field).LookupList), ((SPFieldLookup)FieldControl.Field).LookupField, FieldControl.Filter.IsMulti, FieldControl.Locale);

            cell.Controls.Add(iLookup);

            TableCell inpCell = (TableCell)iLookup.FindControl("containerCell");
            inpCell.Width = Unit.Pixel(TextBoxWidth);
            inpCell.BorderStyle = System.Web.UI.WebControls.BorderStyle.Solid;
            inpCell.BorderWidth = 1;

            // И сделаем очистку на клиенте
            btnClear.OnClientClick = String.Format("javascript:document.getElementById('{0}').innerHTML='';", iLookup.FindControl("upLevelDiv").ClientID);

            // Кастомный валидатор -просто не дает провалиться с незаполненными значениями
            CustomValidator cVal = new CustomValidator();
            cVal.EnableClientScript = true;
            cVal.ServerValidate += new ServerValidateEventHandler(ServerValidate);
            cVal.Display = ValidatorDisplay.None;
            cell.Controls.Add(cVal);
        }

        protected virtual void ServerValidate(object source, ServerValidateEventArgs args)
        {
            args.IsValid = iLookup.ResolveAllEntities();
        }

    }

    /// <summary>
    /// Контрол для полей типа User
    /// </summary>
    class PeopleInputControl : BaseInputControl
    {

        protected PeopleEditor iLookup;

        public override String Value
        {
            get
            {
                EnsureChildControls();

                List<String> vals = new List<String>();

                foreach (PickerEntity ent in iLookup.Entities)
                {
                    if (FieldControl.Filter.UseLookupId)
                    {
                        // Ключ - logon юзера, надо перевести в id
                        SPUser user = null;
                        try
                        {
                            user = FieldControl.Field.ParentList.ParentWeb.EnsureUser(ent.Key);
                        }
                        catch (Exception) { }
                        if (user != null)
                            vals.Add(user.ID.ToString());
                    }
                    else
                        vals.Add(ent.DisplayText);
                }

                return vals.Count == 0 ? null : String.Join(String.IsNullOrEmpty(this.FieldControl.Filter.Delimiter) ? Filter.DefaultDelimiter : this.FieldControl.Filter.Delimiter, vals.ToArray());
            }
            set
            {
                EnsureChildControls();

                iLookup.Entities.Clear();
                string[] vals = { };
                if (!String.IsNullOrEmpty(value))
                {
                    vals = FieldControl.Filter.IsMulti ? value.Split(new string[] { FieldControl.Filter.Delimiter }, StringSplitOptions.RemoveEmptyEntries) : new string[] { value };

                    foreach (String val in vals)
                    {
                        SPUser user = null;

                        try
                        {
                            if (FieldControl.Filter.UseLookupId)
                            // Ищем по ID
                            {
                                int id = -1;
                                if (Int32.TryParse(val, out id) && id > 0)
                                    user = FieldControl.Field.ParentList.ParentWeb.AllUsers.GetByID(id);
                            }
                            else
                            // Ищем по Display Name
                            {
                                user = (from u in FieldControl.Field.ParentList.ParentWeb.AllUsers.Cast<SPUser>() where u.Name.Equals(val) select u).FirstOrDefault();

                            }

                        }
                        catch (Exception) { }

                        if (user != null)
                        {
                            PickerEntity entity = new PickerEntity();
                            entity.Key = user.LoginName;
                            entity.DisplayText = user.Name;
                            entity = iLookup.ValidateEntity(entity);
                            if (entity.IsResolved)
                                iLookup.Entities.Add(entity);

                        }


                    }
                }

            }
        }

        protected override void addInputControls(TableCell cell)
        {

            iLookup = new PeopleEditor()
            {
                ID = String.Format("pic{0}_{1}", FieldControl.Id, FieldControl.Filter.Value),
                CssClass = "ms-usereditor",
                MultiSelect = FieldControl.Filter.IsMulti,
                ToolTip = this.ToolTip
            };

            cell.Controls.Add(iLookup);

            TableCell inpCell = (TableCell)iLookup.FindControl("containerCell");

            inpCell.Width = Unit.Pixel(TextBoxWidth);
            inpCell.BorderStyle = System.Web.UI.WebControls.BorderStyle.Solid;
            inpCell.BorderWidth = 1;


            // И сделаем очистку на клиенте
            btnClear.OnClientClick = String.Format("javascript:document.getElementById('{0}').innerHTML='';", iLookup.FindControl("upLevelDiv").ClientID);


            // Кастомный валидатор - просто не дает провалиться с незаполненными значениями
            CustomValidator cVal = new CustomValidator();
            cVal.EnableClientScript = true;
            cVal.ServerValidate += new ServerValidateEventHandler(ServerValidate);
            cVal.Display = ValidatorDisplay.None;
            cell.Controls.Add(cVal);

        }

        protected virtual void ServerValidate(object source, ServerValidateEventArgs args)
        {
            foreach (PickerEntity ent in iLookup.Entities)
            {
                if (!ent.IsResolved)
                {
                    args.IsValid = false;
                    return;
                }
            }
            args.IsValid = true;
        }
    }

    #region Custom field type conmtrols

    /// <summary>
    /// Контрол для полей типа MyLookup
    /// </summary>
    //class MyLookupInputControl : BaseInputControl
    //{

    //    protected MyLookupFieldPicker iLookup;

    //    public override String Value
    //    {
    //        get
    //        {
    //            EnsureChildControls();
    //            return iLookup.Value;
    //        }
    //        set
    //        {
    //            EnsureChildControls();
    //            iLookup.Value = value;
    //        }
    //    }

    //    protected override void addInputControls(TableCell cell)
    //    {

    //        iLookup = new MyLookupFieldPicker()
    //        {
    //            ID = String.Format("lic{0}_{1}", FieldControl.Id, FieldControl.Filter.Value),
    //            CssClass = "ms-usereditor",
    //            AllowEmpty = true,
    //            AllowTypeIn = true,
    //            MultiSelect = FieldControl.Filter.IsMulti,
    //            ShowButtons = true,
    //            ReadOnly = false,
    //            ToolTip = this.ToolTip,
    //            Width = TextBoxWidth
    //        };

    //    }

    //}

    #endregion User-defined fields

}
